This tutorial … Scottish Remote Sensing Portal.

Packages

library(lidR)# process LAZ files
library(raster)# deal with raster
library(rayshader) # 3D viz
library(rgl) # interactive plot
library(sf) # spatial class

Area of Interest

motte_point = st_read("data/canmore_point.shp", quiet = TRUE)

motte_buffer = st_buffer(motte_point,dist = 50)

LAZ

Next, I am reading the LAZ files and clipping the point cloud to the extent of immidiate area around the motte.

#read laz files
las = readLAS("data/NX6055_4PPM_LAS_PHASE3.laz")

motte = clip_roi(las, motte_buffer)
#plot lidar point cloud
plot(motte, bg = "white")

rglwidget()

grab and rotate the model !

Digital Elevetion Model

In this step I am running standard alghoritms from LiDR package to compute Digital Surface Model (DSM) and Digitial Terrain Model (DTM).

rgl.clear()
# create dsm and dtm
dsm = grid_canopy(motte, 0.5, pitfree())

# assign coordinate system
crs(dsm) = CRS("+init=epsg:27700")
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj =
## prefer_proj): Discarded datum OSGB_1936 in CRS definition
st_crs(27700)
## Coordinate Reference System:
##   User input: EPSG:27700 
##   wkt:
## PROJCRS["OSGB 1936 / British National Grid",
##     BASEGEOGCRS["OSGB 1936",
##         DATUM["OSGB 1936",
##             ELLIPSOID["Airy 1830",6377563.396,299.3249646,
##                 LENGTHUNIT["metre",1]]],
##         PRIMEM["Greenwich",0,
##             ANGLEUNIT["degree",0.0174532925199433]],
##         ID["EPSG",4277]],
##     CONVERSION["British National Grid",
##         METHOD["Transverse Mercator",
##             ID["EPSG",9807]],
##         PARAMETER["Latitude of natural origin",49,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8801]],
##         PARAMETER["Longitude of natural origin",-2,
##             ANGLEUNIT["degree",0.0174532925199433],
##             ID["EPSG",8802]],
##         PARAMETER["Scale factor at natural origin",0.9996012717,
##             SCALEUNIT["unity",1],
##             ID["EPSG",8805]],
##         PARAMETER["False easting",400000,
##             LENGTHUNIT["metre",1],
##             ID["EPSG",8806]],
##         PARAMETER["False northing",-100000,
##             LENGTHUNIT["metre",1],
##             ID["EPSG",8807]]],
##     CS[Cartesian,2],
##         AXIS["(E)",east,
##             ORDER[1],
##             LENGTHUNIT["metre",1]],
##         AXIS["(N)",north,
##             ORDER[2],
##             LENGTHUNIT["metre",1]],
##     USAGE[
##         SCOPE["Engineering survey, topographic mapping."],
##         AREA["United Kingdom (UK) - offshore to boundary of UKCS within 49°45'N to 61°N and 9°W to 2°E; onshore Great Britain (England, Wales and Scotland). Isle of Man onshore."],
##         BBOX[49.75,-9,61.01,2.01]],
##     ID["EPSG",27700]]
# create dtm
dtm = grid_terrain(motte, 0.5, algorithm = knnidw(k = 6L, p = 2))

# addign coordinate system
crs(dtm) = CRS("+init=epsg:27700")
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj =
## prefer_proj): Discarded datum OSGB_1936 in CRS definition
par(mfrow = c(1,2))
plot(dtm, main = "DTM", col = height.colors(50))
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
plot(dsm, main = "DSM",col = height.colors(50))
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

Hillshade

# dsm
slope_dsm = terrain(dsm, opt = 'slope')
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
aspect_dsm = terrain(dsm, opt = 'aspect')
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
hill_dsm = hillShade(slope_dsm, aspect_dsm, angle = 40, direction = 270)
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
# dtm
slope_dtm = terrain(dtm, opt = 'slope')
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
aspect_dtm = terrain(dtm, opt = 'aspect')
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
hill_dtm = hillShade(slope_dtm, aspect_dtm, angle = 5, direction = 270)
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
#plot
par(mfrow = c(1,2))
plot(hill_dtm, main = "DTM Hilshade", col = grey.colors(100, start = 0, end = 1), 
     legend = FALSE)
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition
plot(hill_dsm, main = "DSM Hillshade", col = grey.colors(100, start = 0, end = 1))
## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

## Warning in showSRID(uprojargs, format = "PROJ", multiline = "NO", prefer_proj
## = prefer_proj): Discarded datum Unknown based on Airy 1830 ellipsoid in CRS
## definition

3D Model

#And convert it to a matrix:
elmat = raster_to_matrix(dtm)

elmat %>%
  sphere_shade(texture = "imhof1") %>%
  add_shadow(ray_shade(elmat, zscale = 0.5, sunaltitude = 30,lambert = TRUE),
             max_darken = 1) %>%
  add_shadow(lamb_shade(elmat,zscale = 0.5,sunaltitude = 30), max_darken = 0.2) %>%
  add_shadow(ambient_shade(elmat, zscale = 0.5), max_darken = 0.2) %>%
  plot_3d(elmat, zscale = 0.5,windowsize = c(1000,1000),
          phi = 40, theta = 180, zoom = 0.8, fov = 1)
rglwidget()

grab and rotate the model !

Another example …

Tantallon Castle And here is the code

library(rayshader)
library(raster)
library(magick)
library(gifski)

dem = raster("data/tantallon.tif")

n_frames <- 41

elmat = raster_to_matrix(dem)

zscale <- 0.5

waterdepthvalues <- c(0:20, seq(19,0,-1)) / 2

phi_values = seq(20,60)

waterdepthvalues * zscale

length(waterdepthvalues)

img_frames <- paste0("drain", seq_len(n_frames), ".png")

for (i in seq_len(n_frames)) {
elmat %>%
  sphere_shade(texture = "imhof1") %>%
  add_shadow(ray_shade(elmat, zscale = 0.5, sunaltitude = 30,lambert = TRUE),
             max_darken = 1) %>%
  add_shadow(lamb_shade(elmat,zscale = 0.5,sunaltitude = 30), max_darken = 0.2) %>%
  add_shadow(ambient_shade(elmat, zscale = 0.5), max_darken = 0.2) %>%
  plot_3d(elmat, zscale = 0.5,windowsize = c(1000,1000),
          water = TRUE, watercolor = "imhof3", wateralpha = 0.5, 
          waterlinecolor = "#ffffff", waterlinealpha = 0.5,
          waterdepth = waterdepthvalues[i],
          phi = 50, theta = 45, zoom = 0.8, fov = 1)
  render_snapshot(filename = img_frames[i],
                  title_text = "Tantallon Castle", 
                  title_font = "Helvetica",
                  vignette = TRUE,
                  title_size = 50,
                  title_color = "black")
  rgl::clear3d()
}

magick::image_write_gif(magick::image_read(img_frames), 
                        path = "tantallon.gif", 
                        delay = 6/n_frames)
sessionInfo()
## R version 4.0.2 (2020-06-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Mojave 10.14.6
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] sf_1.0-2         rgl_0.100.54     rayshader_0.15.1 lidR_3.1.4      
## [5] raster_3.1-5     sp_1.4-5        
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.7              lattice_0.20-41         png_0.1-7              
##  [4] prettyunits_1.1.1       class_7.3-17            digest_0.6.27          
##  [7] foreach_1.5.0           utf8_1.2.2              mime_0.11              
## [10] R6_2.5.1                evaluate_0.14           e1071_1.7-4            
## [13] highr_0.9               pillar_1.6.2            rlang_0.4.11           
## [16] progress_1.2.2          lazyeval_0.2.2          data.table_1.14.0      
## [19] miniUI_0.1.1.1          jquerylib_0.1.4         magick_2.3             
## [22] rmarkdown_2.10.1        rgdal_1.5-18            webshot_0.5.2          
## [25] stringr_1.4.0.9000      htmlwidgets_1.5.1       munsell_0.5.0          
## [28] shiny_1.4.0.2           compiler_4.0.2          httpuv_1.5.4           
## [31] xfun_0.25               pkgconfig_2.0.3         rgeos_0.5-2            
## [34] htmltools_0.5.1.1       tidyselect_1.1.0        tibble_3.1.4           
## [37] codetools_0.2-16        fansi_0.5.0             crayon_1.4.1           
## [40] dplyr_1.0.2             later_1.1.0.1           grid_4.0.2             
## [43] jsonlite_1.7.2          xtable_1.8-4            lifecycle_1.0.0        
## [46] DBI_1.1.0               magrittr_2.0.1          scales_1.1.1           
## [49] units_0.6-7             KernSmooth_2.23-17      stringi_1.7.3          
## [52] promises_1.1.1          doParallel_1.0.15       bslib_0.2.5.1          
## [55] ellipsis_0.3.2          vctrs_0.3.8             generics_0.1.0         
## [58] iterators_1.0.12        tools_4.0.2             manipulateWidget_0.10.1
## [61] glue_1.4.2              purrr_0.3.4             hms_0.5.3              
## [64] crosstalk_1.1.0.1       parallel_4.0.2          fastmap_1.0.1          
## [67] yaml_2.2.1              colorspace_2.0-2        rlas_1.3.5             
## [70] classInt_0.4-3          knitr_1.33              sass_0.4.0
 
Logo

Geographic Information Science and Analysis Team

LS0tCnRpdGxlOiAiU2NvdHRpc2ggR292ZXJubWVudCBMaURBUiAtIFR1dG9yaWFsIHVzaW5nIFIiCmF1dGhvcjogImJ5IE1pY2hhbCBNaWNoYWxza2kgLSBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogZmxhdGx5CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogCiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogIAotLS0KCjxzdHlsZT4KCmRpdi5ibHVlIHsgY29sb3I6ICNGRkZGRkYgO2JhY2tncm91bmQtY29sb3I6ICMyOTNlNTE7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMjBweDsgfQoKPC9zdHlsZT4KCjxkaXYgY2xhc3MgPSAiYmx1ZSI+CgpUaGlzIHR1dG9yaWFsIC4uLiBbU2NvdHRpc2ggUmVtb3RlIFNlbnNpbmcgUG9ydGFsXShodHRwczovL3JlbW90ZXNlbnNpbmdkYXRhLmdvdi5zY290LykuCgo8L2Rpdj4KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBQYWNrYWdlcwoKYGBge3IgcGFja2FnZXMsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9CmxpYnJhcnkobGlkUikjIHByb2Nlc3MgTEFaIGZpbGVzCmxpYnJhcnkocmFzdGVyKSMgZGVhbCB3aXRoIHJhc3RlcgpsaWJyYXJ5KHJheXNoYWRlcikgIyAzRCB2aXoKbGlicmFyeShyZ2wpICMgaW50ZXJhY3RpdmUgcGxvdApsaWJyYXJ5KHNmKSAjIHNwYXRpYWwgY2xhc3MKCmBgYAoKCiMgQXJlYSBvZiBJbnRlcmVzdAoKYGBge3J9Cm1vdHRlX3BvaW50ID0gc3RfcmVhZCgiZGF0YS9jYW5tb3JlX3BvaW50LnNocCIsIHF1aWV0ID0gVFJVRSkKCm1vdHRlX2J1ZmZlciA9IHN0X2J1ZmZlcihtb3R0ZV9wb2ludCxkaXN0ID0gNTApCgpgYGAKCiMgTEFaCgpOZXh0LCBJIGFtIHJlYWRpbmcgdGhlIExBWiBmaWxlcyBhbmQgY2xpcHBpbmcgdGhlIHBvaW50IGNsb3VkIHRvIHRoZSBleHRlbnQgb2YgaW1taWRpYXRlIGFyZWEgYXJvdW5kIHRoZSBtb3R0ZS4KYGBge3IgbGFzfQojcmVhZCBsYXogZmlsZXMKbGFzID0gcmVhZExBUygiZGF0YS9OWDYwNTVfNFBQTV9MQVNfUEhBU0UzLmxheiIpCgptb3R0ZSA9IGNsaXBfcm9pKGxhcywgbW90dGVfYnVmZmVyKQojcGxvdCBsaWRhciBwb2ludCBjbG91ZApwbG90KG1vdHRlLCBiZyA9ICJ3aGl0ZSIpCgpyZ2x3aWRnZXQoKQoKCgpgYGAKCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij5ncmFiIGFuZCByb3RhdGUgdGhlIG1vZGVsICEgPC9hPjwvcD4KCiMgRGlnaXRhbCBFbGV2ZXRpb24gTW9kZWwKCkluIHRoaXMgc3RlcCBJIGFtIHJ1bm5pbmcgc3RhbmRhcmQgYWxnaG9yaXRtcyBmcm9tIExpRFIgcGFja2FnZSB0byBjb21wdXRlIERpZ2l0YWwgU3VyZmFjZSBNb2RlbCAoRFNNKSBhbmQgRGlnaXRpYWwgVGVycmFpbiBNb2RlbCAoRFRNKS4KCmBgYHtyfQpyZ2wuY2xlYXIoKQojIGNyZWF0ZSBkc20gYW5kIGR0bQpkc20gPSBncmlkX2Nhbm9weShtb3R0ZSwgMC41LCBwaXRmcmVlKCkpCgojIGFzc2lnbiBjb29yZGluYXRlIHN5c3RlbQpjcnMoZHNtKSA9IENSUygiK2luaXQ9ZXBzZzoyNzcwMCIpCnN0X2NycygyNzcwMCkKIyBjcmVhdGUgZHRtCmR0bSA9IGdyaWRfdGVycmFpbihtb3R0ZSwgMC41LCBhbGdvcml0aG0gPSBrbm5pZHcoayA9IDZMLCBwID0gMikpCgojIGFkZGlnbiBjb29yZGluYXRlIHN5c3RlbQpjcnMoZHRtKSA9IENSUygiK2luaXQ9ZXBzZzoyNzcwMCIpCgpwYXIobWZyb3cgPSBjKDEsMikpCnBsb3QoZHRtLCBtYWluID0gIkRUTSIsIGNvbCA9IGhlaWdodC5jb2xvcnMoNTApKQpwbG90KGRzbSwgbWFpbiA9ICJEU00iLGNvbCA9IGhlaWdodC5jb2xvcnMoNTApKQoKYGBgCgojIEhpbGxzaGFkZQoKYGBge3J9CiMgZHNtCnNsb3BlX2RzbSA9IHRlcnJhaW4oZHNtLCBvcHQgPSAnc2xvcGUnKQphc3BlY3RfZHNtID0gdGVycmFpbihkc20sIG9wdCA9ICdhc3BlY3QnKQpoaWxsX2RzbSA9IGhpbGxTaGFkZShzbG9wZV9kc20sIGFzcGVjdF9kc20sIGFuZ2xlID0gNDAsIGRpcmVjdGlvbiA9IDI3MCkKCiMgZHRtCnNsb3BlX2R0bSA9IHRlcnJhaW4oZHRtLCBvcHQgPSAnc2xvcGUnKQphc3BlY3RfZHRtID0gdGVycmFpbihkdG0sIG9wdCA9ICdhc3BlY3QnKQpoaWxsX2R0bSA9IGhpbGxTaGFkZShzbG9wZV9kdG0sIGFzcGVjdF9kdG0sIGFuZ2xlID0gNSwgZGlyZWN0aW9uID0gMjcwKQoKI3Bsb3QKcGFyKG1mcm93ID0gYygxLDIpKQpwbG90KGhpbGxfZHRtLCBtYWluID0gIkRUTSBIaWxzaGFkZSIsIGNvbCA9IGdyZXkuY29sb3JzKDEwMCwgc3RhcnQgPSAwLCBlbmQgPSAxKSwgCiAgICAgbGVnZW5kID0gRkFMU0UpCnBsb3QoaGlsbF9kc20sIG1haW4gPSAiRFNNIEhpbGxzaGFkZSIsIGNvbCA9IGdyZXkuY29sb3JzKDEwMCwgc3RhcnQgPSAwLCBlbmQgPSAxKSkKYGBgCgojIDNEIE1vZGVsCgpgYGB7cn0KI0FuZCBjb252ZXJ0IGl0IHRvIGEgbWF0cml4OgplbG1hdCA9IHJhc3Rlcl90b19tYXRyaXgoZHRtKQoKZWxtYXQgJT4lCiAgc3BoZXJlX3NoYWRlKHRleHR1cmUgPSAiaW1ob2YxIikgJT4lCiAgYWRkX3NoYWRvdyhyYXlfc2hhZGUoZWxtYXQsIHpzY2FsZSA9IDAuNSwgc3VuYWx0aXR1ZGUgPSAzMCxsYW1iZXJ0ID0gVFJVRSksCiAgICAgICAgICAgICBtYXhfZGFya2VuID0gMSkgJT4lCiAgYWRkX3NoYWRvdyhsYW1iX3NoYWRlKGVsbWF0LHpzY2FsZSA9IDAuNSxzdW5hbHRpdHVkZSA9IDMwKSwgbWF4X2RhcmtlbiA9IDAuMikgJT4lCiAgYWRkX3NoYWRvdyhhbWJpZW50X3NoYWRlKGVsbWF0LCB6c2NhbGUgPSAwLjUpLCBtYXhfZGFya2VuID0gMC4yKSAlPiUKICBwbG90XzNkKGVsbWF0LCB6c2NhbGUgPSAwLjUsd2luZG93c2l6ZSA9IGMoMTAwMCwxMDAwKSwKICAgICAgICAgIHBoaSA9IDQwLCB0aGV0YSA9IDE4MCwgem9vbSA9IDAuOCwgZm92ID0gMSkKcmdsd2lkZ2V0KCkKYGBgCgo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+Z3JhYiBhbmQgcm90YXRlIHRoZSBtb2RlbCAhIDwvYT48L3A+CgoKQW5vdGhlciBleGFtcGxlIC4uLgoKIVtUYW50YWxsb24gQ2FzdGxlXShpbWcvdGFudGFsbG9uLmdpZikKQW5kIGhlcmUgaXMgdGhlIGNvZGUKCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9RkFMU0V9CmxpYnJhcnkocmF5c2hhZGVyKQpsaWJyYXJ5KHJhc3RlcikKbGlicmFyeShtYWdpY2spCmxpYnJhcnkoZ2lmc2tpKQoKZGVtID0gcmFzdGVyKCJkYXRhL3RhbnRhbGxvbi50aWYiKQoKbl9mcmFtZXMgPC0gNDEKCmVsbWF0ID0gcmFzdGVyX3RvX21hdHJpeChkZW0pCgp6c2NhbGUgPC0gMC41Cgp3YXRlcmRlcHRodmFsdWVzIDwtIGMoMDoyMCwgc2VxKDE5LDAsLTEpKSAvIDIKCnBoaV92YWx1ZXMgPSBzZXEoMjAsNjApCgp3YXRlcmRlcHRodmFsdWVzICogenNjYWxlCgpsZW5ndGgod2F0ZXJkZXB0aHZhbHVlcykKCmltZ19mcmFtZXMgPC0gcGFzdGUwKCJkcmFpbiIsIHNlcV9sZW4obl9mcmFtZXMpLCAiLnBuZyIpCgpmb3IgKGkgaW4gc2VxX2xlbihuX2ZyYW1lcykpIHsKZWxtYXQgJT4lCiAgc3BoZXJlX3NoYWRlKHRleHR1cmUgPSAiaW1ob2YxIikgJT4lCiAgYWRkX3NoYWRvdyhyYXlfc2hhZGUoZWxtYXQsIHpzY2FsZSA9IDAuNSwgc3VuYWx0aXR1ZGUgPSAzMCxsYW1iZXJ0ID0gVFJVRSksCiAgICAgICAgICAgICBtYXhfZGFya2VuID0gMSkgJT4lCiAgYWRkX3NoYWRvdyhsYW1iX3NoYWRlKGVsbWF0LHpzY2FsZSA9IDAuNSxzdW5hbHRpdHVkZSA9IDMwKSwgbWF4X2RhcmtlbiA9IDAuMikgJT4lCiAgYWRkX3NoYWRvdyhhbWJpZW50X3NoYWRlKGVsbWF0LCB6c2NhbGUgPSAwLjUpLCBtYXhfZGFya2VuID0gMC4yKSAlPiUKICBwbG90XzNkKGVsbWF0LCB6c2NhbGUgPSAwLjUsd2luZG93c2l6ZSA9IGMoMTAwMCwxMDAwKSwKICAgICAgICAgIHdhdGVyID0gVFJVRSwgd2F0ZXJjb2xvciA9ICJpbWhvZjMiLCB3YXRlcmFscGhhID0gMC41LCAKICAgICAgICAgIHdhdGVybGluZWNvbG9yID0gIiNmZmZmZmYiLCB3YXRlcmxpbmVhbHBoYSA9IDAuNSwKICAgICAgICAgIHdhdGVyZGVwdGggPSB3YXRlcmRlcHRodmFsdWVzW2ldLAogICAgICAgICAgcGhpID0gNTAsIHRoZXRhID0gNDUsIHpvb20gPSAwLjgsIGZvdiA9IDEpCiAgcmVuZGVyX3NuYXBzaG90KGZpbGVuYW1lID0gaW1nX2ZyYW1lc1tpXSwKICAgICAgICAgICAgICAgICAgdGl0bGVfdGV4dCA9ICJUYW50YWxsb24gQ2FzdGxlIiwgCiAgICAgICAgICAgICAgICAgIHRpdGxlX2ZvbnQgPSAiSGVsdmV0aWNhIiwKICAgICAgICAgICAgICAgICAgdmlnbmV0dGUgPSBUUlVFLAogICAgICAgICAgICAgICAgICB0aXRsZV9zaXplID0gNTAsCiAgICAgICAgICAgICAgICAgIHRpdGxlX2NvbG9yID0gImJsYWNrIikKICByZ2w6OmNsZWFyM2QoKQp9CgptYWdpY2s6OmltYWdlX3dyaXRlX2dpZihtYWdpY2s6OmltYWdlX3JlYWQoaW1nX2ZyYW1lcyksIAogICAgICAgICAgICAgICAgICAgICAgICBwYXRoID0gInRhbnRhbGxvbi5naWYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgZGVsYXkgPSA2L25fZnJhbWVzKQpgYGAKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoKJm5ic3A7CjxociAvPgo8Y2VudGVyPgo8aW1nIHNyYz0iaHR0cHM6Ly9yZW1vdGVzZW5zaW5nZGF0YS5nb3Yuc2NvdC9zY290Z292bG9nby4zOGE3M2Y2OC5zdmciIGFsdCA9ICJMb2dvIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjEwMCI+CjwvY2VudGVyPgo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+R2VvZ3JhcGhpYyBJbmZvcm1hdGlvbiBTY2llbmNlIGFuZCBBbmFseXNpcyBUZWFtPC9wPgo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PHNwYW4+PGVtPkdJLVNBVEBnb3Yuc2NvdDwvZW0+PC9zcGFuPjwvcD4K